package com.example.mq.server.core;

import com.example.mq.common.MqException;

/**
 * 使用这个类来实现交换机的转发规则
 * 同时实现方法检查bindingKey是否合法
 */
public class Router {

    /**
     * 数字,字母,下划线
     * 使用.分割成若干部分
     * 允许使用* #来通配独立的分段 aaa.*.bbb 对  aaa.a*.bbb 错 单独存在
     * @param bindingKey
     * @return
     */
    public boolean checkBindingKey(String bindingKey){
        if(bindingKey.length() == 0){
            // 直接交换机 && fanout交换机用不上
            return true;
        }
        String[] split = bindingKey.split("\\.");
        for (int i = 0; i<split.length; i++) {
            String s = split[i];
            /*
             * 约定一下通配符之间的相邻关系
             * 1.aaa.#.#.bbb ×
             * 2.aaa.#.*.bbb ×
             * 3.aaa.*.#.bbb ×
             * 4.aaa.*.*.bbb √
             * 前三种实现繁琐咔叽掉
             * */
            if(i != 0 && split[i-1].length() == 1 && s.length() == 1 && (!split[i-1].equals("*") || !s.equals("*"))){
                return false;
            }
            if(!s.matches("^[0-9a-zA-Z_*#]+")){
                return false;
            }
        }
        return true;
    }

    public boolean checkRoutingKey(String routingKey){
        if(routingKey.equals("")){
            return true;
        }
        String[] split = routingKey.split("\\.");
        for (String s : split) {
            if(!s.matches("^[0-9a-zA-Z_]+")){
                return false;
            }
        }
        return true;
    }

    public boolean route(ExchangeType exchangeType, Binding binding, Message message) throws MqException {
        // 根据不同的 exchangeType 使用不同的转发规则
        if(exchangeType == ExchangeType.FANOUT){
            // 全部转发
            return true;
        }else if(exchangeType == ExchangeType.TOPIC){
            return routeTopic(binding,message);
        }else{
            throw new MqException("[Router] 交换机类型非法! exchangeType = "+exchangeType);
        }
    }

    private boolean routeTopic(Binding binding, Message message) throws MqException {
        String bindingKey = binding.getBindingKey();
        String routingKey = message.getRoutingKey();

        String[] s1 = bindingKey.split("\\.");
        String[] s2 = routingKey.split("\\.");
        int i = 0,j = 0;
        while(i<s1.length && j <s2.length){
            if(!s1[i].equals(s2[j]) && !s1[i].equals("*") && !s1[i].equals("#")){
                return false;
            }

            if(s1[i].equals(s2[j]) || s1[i].equals("*")){
                i++;
                j++;
                continue;
            }
            if(s1[i].equals("#") && i == s1.length-1) return true;
            while(s1[i].equals("#")){
                if(s1[i+1].equals(s2[j])){
                    i+=2;
                    j++;
                    break;
                }
                j++;
            }
        }
        return i == s1.length && j == s2.length;
    }
}
